package edu.caece.automaton;

import java.util.Iterator;
import java.util.Set;

public class FiniteStateAutomatonImpl extends AbstractAutomaton{

	public boolean run(String word) {
		int index = 0;
		this.currentState = this.startState;
		Iterator<Transition> transitionIterator;
		Transition testTransition;
		boolean stateChanged;

		while (index < word.length() && !this.currentState.equals(this.trashState)){
			stateChanged = false;
			if (this.transitions.containsKey(this.currentState)){
				transitionIterator = transitions.get(this.currentState).iterator();
				while (transitionIterator.hasNext() && !stateChanged){
					testTransition = transitionIterator.next();
					if (testTransition.getSourceState().equals(this.currentState)){
						if (testTransition.matches(word.charAt(index))){							
							this.currentState = testTransition.getDestinationState();
							stateChanged = true;
							LOGGER.debug(testTransition.toString());
						}
					}
					
				}
			}
			if (!stateChanged)
				this.currentState = this.trashState;
			index++;
		}

		return this.acceptStates.contains(this.currentState);
	}
	
	@Override 
	public void reset(){
		this.currentState = this.startState;
	}

	@Override
	public boolean step(Character character) {
		Iterator<Transition> transitionIterator;
		Transition testTransition;
		boolean stateChanged;

		if (!this.currentState.equals(this.trashState)){
			stateChanged = false;
			if (this.transitions.containsKey(this.currentState)){
				transitionIterator = transitions.get(this.currentState).iterator();
				while (transitionIterator.hasNext() && !stateChanged){
					testTransition = transitionIterator.next();
					if (testTransition.getSourceState().equals(this.currentState)){
						if (testTransition.matches(character)){
							this.currentState = testTransition.getDestinationState();
							stateChanged = true;
							LOGGER.debug(testTransition.toString());
						}
					}
					
				}
			}
			if (!stateChanged){
				this.currentState = this.trashState;
				LOGGER.debug(this.trashState.toString());
			}
		}
		return this.acceptStates.contains(this.currentState);
	}

	@Override
	public State peek(Character character) {
		Iterator<Transition> transitionIterator;
		Transition testTransition;
		boolean stateChanged = false;
		State peekState = null;
		
		if (!this.currentState.equals(this.trashState)){
			stateChanged = false;
			if (this.transitions.containsKey(this.currentState)){
				transitionIterator = transitions.get(this.currentState).iterator();
				while (transitionIterator.hasNext() && !stateChanged){
					testTransition = transitionIterator.next();
					if (testTransition.getSourceState().equals(this.currentState)){
						if (testTransition.matches(character)){
							peekState = testTransition.getDestinationState();
							stateChanged = true;
							LOGGER.debug(testTransition.toString());
						}
					}
					
				}
			}
		}
		if (!stateChanged){
			peekState = this.trashState;
			LOGGER.debug(peekState.toString());
		}
		return peekState;
	}

	public Set<State> getAcceptStates() {
		return this.acceptStates;
	}
}
